package com.eddie.linkedlist;

import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Eddie
 */
public class Joseph {

    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.add(5);
//        circleSingleLinkedList.showBoy();
        circleSingleLinkedList.countBoy(1,2,5);
    }

}

/**
 * 创建一个单向的环形链表
 */
class CircleSingleLinkedList {
    /**
     * 创建一个first节点，当前没有编号
     */
    private Boy first = null;

    /**
     * 添加小孩节点，构建成一个环形链表
     */
    public void add(int nums) {
        if (nums > 0) {
            //辅助指针，帮助构建环形链表
            Boy curBoy = null;
            for (int i = 1; i <= nums; i++) {
                Boy boy = new Boy(i);
                if (i == 1) {
                    first = boy;
                    first.setNext(first);
                    curBoy = first;
                } else {
                    curBoy.setNext(boy);
                    boy.setNext(first);
                    curBoy = boy;
                }

            }
        }
    }

    /**
     * 遍历当前环形链表
     */
    public void showBoy() {
        Boy curBoy = first;
        while (curBoy != null) {
            System.out.printf("小孩的编号%d \n", curBoy.getNo());
            curBoy = curBoy.getNext();
            if (curBoy == first) break;
        }
    }

    /**
     * 根据用户的输入，计算出出圈的顺序
     *
     * @param startNo  表示从第几个小孩开始数数
     * @param countNum 表示数几下
     * @param nums     表示最初有多少小孩
     */
    public void countBoy(int startNo, int countNum, int nums) {
        //先对数据进行校验
        if (first == null || startNo <= 0 || startNo > nums) {
            System.out.println("请重新输入");
            return;
        }
        //创建辅助指针，帮助完成小孩出圈
        Boy helper = first;
        //需求创建一个辅助指针helper，事先应该指向环形链表最后这个节点
        //说明这个是helper指向了最后一个节点
        while (helper.getNext() != first) {
            helper = helper.getNext();
        }
        //小孩报数前，先让first和helper移动k-1次
        for (int i = 0; i < startNo - 1; i++) {
            first = first.getNext();
            helper = helper.getNext();
        }
        //让f，h同时移动m-1次，然后出圈
        //循环操作，直到圈中只有一个节点
        while (helper != first) {
            //让fh同时移动countNum-1,然后出圈
            for (int i = 0; i < countNum - 1; i++) {
                first = first.getNext();
                helper = helper.getNext();
            }
            //这时first指向的节点就是要出圈的小孩节点
            System.out.printf("小孩%d出圈\n", first.getNo());
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留在圈中的小孩编号是：%d\n", first.getNo());
    }
}

/**
 * 创建一个boy类表示一个节点
 */
@Data
@NoArgsConstructor
class Boy {
    private int no;
    /**
     * 指向下一个节点，默认null
     */
    private Boy next;

    public Boy(int no) {
        this.no = no;
    }
}
